package com.ruoyi.activiti.util;

import cn.hutool.core.collection.CollectionUtil;
import com.ruoyi.activiti.domain.MyHistoricTask;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.*;
import org.activiti.engine.ActivitiException;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Service
public class ActivitiUtil {

    /**
     * 获取当前节点的前一用户任务（执行过的）
     * @param process
     * @param currentNode
     * @param histTasks
     * @return
     */
    public FlowNode getLastUserTask(Process process, FlowNode currentNode, List<MyHistoricTask> histTasks){
        return getLastUserTask(process, currentNode, histTasks, new HashSet<>());
    }

    private FlowNode getLastUserTask(Process process, FlowNode currentNode, List<MyHistoricTask> histTasks, Set<String> ids){//获取当前节点的上一用户（用户执行过的）
        if(CollectionUtil.isEmpty(histTasks) || histTasks.size()<=1){
            throw new ActivitiException("当前流程没有处理过");
        }
        List<SequenceFlow> incomingFlows = currentNode.getIncomingFlows();//获取到当前节点的进入连线
        if(CollectionUtil.isEmpty(incomingFlows)){
            return null;
        }
        FlowNode fromNode;
        for (SequenceFlow incomingFlow : incomingFlows) {
            fromNode = (FlowNode)incomingFlow.getSourceFlowElement();//获取来源节点
            if(fromNode instanceof UserTask){//如是用户任务则进行处理
                String taskDefKey = fromNode.getId();//这里可能要做环形调用的判断
                for (MyHistoricTask histTask : histTasks) {
                    if(taskDefKey.equals(histTask.getTaskDefinitionKey())){
                        return fromNode;
                    }
                }
            }
            return getLastUserTask(process, currentNode, histTasks, ids);//否则继续向前递归
        }
        return null;
    }

    /**
     * 获取当前节点的下一用户任务
     * @param process
     * @param currentNode
     * @param histTasks 不传则可以查询未处理过的节点
     * @return
     */
    public FlowNode getNextUserTask(Process process, FlowNode currentNode, List<MyHistoricTask> histTasks){
        Set<FlowNode> nodes = this.getNextUserTasks(process, currentNode, histTasks);
        if(CollectionUtil.isEmpty(nodes)){
            return null;
        }else if(nodes.size()>1){
            throw new ActivitiException("当前节点的下一用户任务不唯一");
        }else{
            for (FlowNode node : nodes) {
                return node;
            }
        }
        return null;
    }

    public Set<FlowNode> getNextUserTasks(Process process, FlowNode currentNode, List<MyHistoricTask> histTasks){
        return getNextUserTasks(process, currentNode, histTasks, new HashSet<>());
    }

    private Set<FlowNode> getNextUserTasks(Process process, FlowNode currentNode, List<MyHistoricTask> histTasks, Set<String> ids){
        List<SequenceFlow> outgoingFlows = currentNode.getOutgoingFlows();//获取到当前节点的进入连线
        if(CollectionUtil.isEmpty(outgoingFlows)){
            return null;
        }
        FlowNode toNode;
        Set<FlowNode> nodes = new HashSet<>();
        for (SequenceFlow outFlow : outgoingFlows) {
            toNode = (FlowNode)outFlow.getTargetFlowElement();//获取目标节点
            if(toNode instanceof UserTask){//如是用户任务则直接保存
                if(CollectionUtil.isNotEmpty(histTasks)){
                    String taskDefKey = toNode.getId();//这里可能要做环形调用的判断
                    for (MyHistoricTask histTask : histTasks) {
                        if(taskDefKey.equals(histTask.getTaskDefinitionKey())){
                            nodes.add(toNode);
                        }
                    }
                }else{
                    nodes.add(toNode);
                }
            }else{//否则继续向前递归
                Set<FlowNode> tmpNodes = this.getNextUserTasks(process, toNode, histTasks);
                if(CollectionUtil.isNotEmpty(tmpNodes)){
                    nodes.addAll(tmpNodes);
                }
            }
        }
        return nodes;
    }

    /**
     * 获取流程图的起始用户任务，流程图必须有唯一的起始用户任务
     * @return
     */
    public FlowNode getFirstUserTask(Process process, List<MyHistoricTask> histTasks){
        List<StartEvent> startNodes = process.findFlowElementsOfType(StartEvent.class);
        if(CollectionUtil.isEmpty(startNodes)){
            throw new ActivitiException("该流程没有开始节点");
        }else if(startNodes.size()>1){
            throw new ActivitiException("该流程开始节点不唯一");
        }
        return this.getNextUserTask(process, startNodes.get(0), histTasks);
    }
}
